#ifndef _L_VECTORS_111225_H
#define _L_VECTORS_111225_H

#include <lmacros.h>
#include <lmath.h>

#define BOOST_FORCE_SYMMETRIC_OPERATORS
#include <boost/operators.hpp>

LLIB_BEGIN;

/* Generic vector class
 */
template <typename T, unsigned N, typename S = Float>
class Vec : public
    boost::totally_ordered< Vec<T,N,S>,
    boost::additive< Vec<T,N,S>,
    boost::multiplicative< Vec<T,N,S>, S > > > {
private:
    typedef Vec<T,N,S> mine_t;
public:
    /* the data field */
    T   cell[N];

    /* the default constructor */
    mine_t() { FOR(I,0,N) cell[I] = T(); }    // make every component set to default

    /* the convenience way to access components */
    inline T& operator [] (Int32 index) { return cell[index]; }
    inline const T& operator [] (Int32 index) const { return cell[index]; }

    /* for totallly ordered operators */
    friend inline Boolean operator == (const mine_t& v1, const mine_t& v2) { FOR(I,0,N) if(v1.cell[I] != v2.cell[I]) return FALSE; return TRUE; }
    friend inline Boolean operator <  (const mine_t& v1, const mine_t& v2) { FOR(I,0,N) if(v1.cell[I] != v2.cell[I]) return v1.cell[I] < v2.cell[I]; return FALSE; }

    /* for additive & multiplicative operators */
    inline void operator += (const mine_t& v) { FOR(I,0,N) cell[I] += v.cell[I]; }
    inline void operator -= (const mine_t& v) { FOR(I,0,N) cell[I] -= v.cell[I]; }
    inline void operator *= (S f) { FOR(I,0,N) cell[I] *= f; }
    inline void operator /= (S f) { FOR(I,0,N) cell[I] /= f; }

    /* the custom operations : cross */
    friend inline S operator * (const mine_t& v1, const mine_t& v2) { S res = 0; FOR(I,0,N) res += v1.cell[I] * v2.cell[I]; return res; }

    /* the custom operations : unary - */
    inline mine_t operator- () const { mine_t res(*this); FOR(I,0,N) res[I] = -cell[I]; return res; }

    /* some common functions */
    inline S SqrLength() const { S res = 0; FOR(I,0,N) res += cell[I] * cell[I]; return res; }
    inline S Length() const { return (S)sqrt(SqrLength()); }
    inline void Normalize() { S l = S(1.0 / Length()); FOR(I,0,N) cell[I] *= l; }

    /* output operator */
    friend inline std::ostream& operator << (std::ostream& os, const mine_t& v) { os << '(' << v.cell[0]; FOR(I,1,N) os << ',' << v.cell[I]; os << ')'; return os; }
};

/* Generic Vector class
 * Partial specialization: 2 dimension version
 * Improved: 1. Better component operation without loop;
 *           2. Component alias x, y;
 *           3. Component define constructor & component setter.
 */
template <typename T, typename S>
class Vec<T,2,S> : public
    boost::totally_ordered< Vec<T,2,S>,
    boost::additive< Vec<T,2,S>,
    boost::multiplicative< Vec<T,2,S>, S > > > {
private:
    typedef Vec<T,2,S> mine_t;
public:
    /* the data field */
    union {
        struct { T cell[2]; };
        struct { T x, y; };
    };

    /* the default constructor */
    mine_t() : x(T()), y(T()) {}    // make every component set to default

    /* the component define constructor */
    mine_t(const T& a_x, const T& a_y) : x(a_x), y(a_y) {}

    /* the component setter */
    inline void Set(const T& a_x, const T& a_y) { x = a_x; y = a_y; }

    /* the convenience way to access components */
    inline T& operator [] (Int32 index) { return cell[index]; }
    inline const T& operator [] (Int32 index) const { return cell[index]; }

    /* for totallly ordered operators */
    friend inline Boolean operator == (const mine_t& v1, const mine_t& v2) { return v1.x == v2.x && v1.y == v2.y; }
    friend inline Boolean operator <  (const mine_t& v1, const mine_t& v2) { return v1.x != v2.x ? v1.x < v2.x : v1.y < v2.y; }

    /* for additive & multiplicative operators */
    inline void operator += (const mine_t& v) { x += v.x; y += v.y; }
    inline void operator -= (const mine_t& v) { x -= v.x; y -= v.y; }
    inline void operator *= (S f) { x *= f; y *= f; }
    inline void operator /= (S f) { x /= f; y /= f; }

    /* the custom operations : cross */
    friend inline S operator * (const mine_t& v1, const mine_t& v2) { return v1.x * v2.x + v1.y * v2.y; }

    /* the custom operations : unary - */
    inline mine_t operator- () const { return mine_t(-x, -y); }

    /* some common functions */
    inline S SqrLength() const { return x * x + y * y; }
    inline S Length() const { return (S)sqrt(SqrLength()); }
    inline void Normalize() { S l = S(1.0 / Length()); x *= l; y *= l; }

    /* output operator */
    friend inline std::ostream& operator << (std::ostream& os, const mine_t& v) { os << '(' << v.cell[0] << ',' << v.cell[1] << ')'; return os; }
};

/* Generic Vector class
 * Partial specialization: 3 dimension version
 * Improved: 1. Better component operation without loop;
 *           2. Component alias x, y, z;
 *           3. Component define constructor & component setter.
 */
template <typename T, typename S>
class Vec<T,3,S> : public
    boost::totally_ordered< Vec<T,3,S>,
    boost::additive< Vec<T,3,S>,
    boost::multiplicative< Vec<T,3,S>, S > > > {
private:
    typedef Vec<T,3,S> mine_t;
public:
    /* the data field */
    union {
        struct { T cell[3]; };
        struct { T x, y, z; };
    };

    /* the default constructor */
    mine_t() : x(T()), y(T()), z(T()) {}    // make every component set to default

    /* the component define constructor */
    mine_t(const T& a_x, const T& a_y, const T& a_z) : x(a_x), y(a_y), z(a_z) {}

    /* set component setter */
    inline void Set(const T& a_x, const T& a_y, const T& a_z) { x = a_x; y = a_y; z = a_z; }

    /* the convenience way to access components */
    inline T& operator [] (Int32 index) { return cell[index]; }
    inline const T& operator [] (Int32 index) const { return cell[index]; }

    /* for totallly ordered operators */
    friend inline Boolean operator == (const mine_t& v1, const mine_t& v2) { return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z; }
    friend inline Boolean operator <  (const mine_t& v1, const mine_t& v2) { return v1.x != v2.x ? v1.x < v2.x : (v1.y != v2.y ? v1.y < v2.y : v1.z < v2.z); }

    /* for additive & multiplicative operators */
    inline void operator += (const mine_t& v) { x += v.x; y += v.y; z += v.z; }
    inline void operator -= (const mine_t& v) { x -= v.x; y -= v.y; z -= v.z; }
    inline void operator *= (S f) { x *= f; y *= f; z *= f; }
    inline void operator /= (S f) { x /= f; y /= f; z /= f; }

    /* the custom operations : cross */
    friend inline S operator * (const mine_t& v1, const mine_t& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; }

    /* the custom operations : unary - */
    inline mine_t operator- () const { return mine_t(-x, -y, -z); }

    /* some common functions */
    inline S SqrLength() const { return x * x + y * y + z * z; }
    inline S Length() const { return (S)sqrt(SqrLength()); }
    inline void Normalize() { S l = S(1.0 / Length()); x *= l; y *= l; z *= l; }

    /* output operator */
    friend inline std::ostream& operator << (std::ostream& os, const mine_t& v) { os << '(' << v.cell[0] << ',' << v.cell[1] << ',' << v.cell[2] << ')'; return os; }

    /* the cross function */
    inline mine_t Cross( mine_t& v ) const { return mine_t( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); }
};

namespace geom {

    typedef Vec<Float,3>    Vec3f;
    typedef Vec<Int32,3>    Vec3i;
    typedef Vec<Float,2>    Vec2f;
    typedef Vec<Int32,2>    Vec2i;

    typedef Vec3f	        Color;
    typedef Vec3f	        Point3f;
    typedef Vec3i	        Point3i;
    typedef Vec2f	        Point2f;
    typedef Vec2i	        Point2i;

}

LLIB_END

#endif //__L_VECTORS__
